home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 25
/
Cream of the Crop 25.iso
/
doom
/
axxwar_1.zip
/
SOURCES
/
BLAZE.QC
< prev
next >
Wrap
Text File
|
1997-03-13
|
18KB
|
739 lines
// AxxWars 0.8
//=============================================================================
// Blaze Gun version 1.2
//
// 2/6/97 by Jonathan E. Wright <nelno@interpath.com>
//
// all original code, not based on anything except the original Quake C
// code from id software.
//=============================================================================
// How it works:
// The flame is simply your basic flame model turned 90 degress on it's side
// when it is shot. When it impacts something that has health > 0 and DAMAGE_AIM
// it sets it's location to that entity's origin, and it's next think becomes
// blaze_stick. blaze_stick is responsible for following the burning entity,
// checking for water, determining if there is another entity nearby to burn
// and burning the entity every so often. The time counter for each burn is kept
// in the flame's attack_finished field, so the entity does not have to be burnt
// each time the flame follows it. When the entity dies, or the flame is submersed
// in water the flame is removed and no more damage is done from that flame.
// if you have solid bodies that are respawnable (ie. in the BodyQue) you
// need to call blaze_switchentity when the bodies are copied or else a
// respawned entity can come back with flames on it.
/*
================
macros
================
*/
$cd id1/models/player_4
$origin 0 -6 24
$base base
$skin skin
//
// running
//
$frame axrun1 axrun2 axrun3 axrun4 axrun5 axrun6
$frame rockrun1 rockrun2 rockrun3 rockrun4 rockrun5 rockrun6
//
// standing
//
$frame stand1 stand2 stand3 stand4 stand5
$frame axstnd1 axstnd2 axstnd3 axstnd4 axstnd5 axstnd6
$frame axstnd7 axstnd8 axstnd9 axstnd10 axstnd11 axstnd12
//
// pain
//
$frame axpain1 axpain2 axpain3 axpain4 axpain5 axpain6
$frame pain1 pain2 pain3 pain4 pain5 pain6
//
// death
//
$frame axdeth1 axdeth2 axdeth3 axdeth4 axdeth5 axdeth6
$frame axdeth7 axdeth8 axdeth9
$frame deatha1 deatha2 deatha3 deatha4 deatha5 deatha6 deatha7 deatha8
$frame deatha9 deatha10 deatha11
$frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8
$frame deathb9
$frame deathc1 deathc2 deathc3 deathc4 deathc5 deathc6 deathc7 deathc8
$frame deathc9 deathc10 deathc11 deathc12 deathc13 deathc14 deathc15
$frame deathd1 deathd2 deathd3 deathd4 deathd5 deathd6 deathd7
$frame deathd8 deathd9
$frame deathe1 deathe2 deathe3 deathe4 deathe5 deathe6 deathe7
$frame deathe8 deathe9
//
// attacks
//
$frame nailatt1 nailatt2
$frame light1 light2
$frame rockatt1 rockatt2 rockatt3 rockatt4 rockatt5 rockatt6
$frame shotatt1 shotatt2 shotatt3 shotatt4 shotatt5 shotatt6
$frame axatt1 axatt2 axatt3 axatt4 axatt5 axatt6
$frame axattb1 axattb2 axattb3 axattb4 axattb5 axattb6
$frame axattc1 axattc2 axattc3 axattc4 axattc5 axattc6
$frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
/*
================
function prototypes
================
*/
void () player_run;
void () BecomeExplosion;
void () SuperDamageSound;
/*
================
global vars
================
*/
// keeps track of the number of flames so that a maximum of flames
// will not be exceeded, causing Quake to bog down
float current_flames;
/*
==================
constants
==================
*/
//float IT_BLAZEGUN = 132;
/*
============
functions
============
*/
void () blaze_precache =
{
precache_model2 ("progs/flame2.mdl");
precache_sound2 ("blaze/flhit1.wav");
precache_sound2 ("blaze/flshot1.wav");
precache_sound2 ("blaze/flhiss1.wav");
};
/*
===============
blaze_extinguishentity
called when a respawnable entity is removed without being killed (ie.
when Cujo is deactivated). Prevents the respawned entity from burning.
===============
*/
/*
void (entity old_ent) blaze_extinguishentity =
{
local entity head, temp;
head = nextent (world);
while (head)
{
head = find (head, classname, "fire");
if ((head != world) && (head.enemy == old_ent))
{
temp = nextent (head);
current_flames = current_flames - 1;
remove (head);
head = temp;
}
else if (head != world) head = nextent (head);
}
};
*/
void (entity old_ent) blaze_extinguishentity =
{
local entity head, temp;
local float i;
local string temp_text;
head = nextent (world);
while (head)
{
if ((head.classname == "fire") && //(vlen (head.origin - old_ent.origin) < 100))
(head.enemy == old_ent))
{
temp = nextent (head);
head.enemy.dmg_inflictor = world;
current_flames = current_flames - 1;
remove (head);
head = temp;
}
else head = nextent (head);
}
};
/*
===============
blaze_switchentity
called when an entities corpse is copied to the body que, prevents the
respawning entity from being still engulfed in flames while the body
can still burn
===============
*/
void (entity old_ent, entity new_ent) blaze_switchentity =
{
local entity head;
head = nextent (world);
while (head)
{
head = find (head, classname, "fire");
if ((head != world) && (head.enemy == old_ent))
{
head.enemy = new_ent;
setorigin (head, new_ent.origin);
}
else if (head != world) head = nextent (head);
}
};
/*
===============
blaze_spread
called by blaze_stick.
creates a new flame entity which will stick to and burn entity "fuel"
===============
*/
void () blaze_stick;
void (entity fuel) blaze_spread =
{
local entity new_flame;
// don't catch the same entity on fire again!
// don't catch anything that can't take damage
// and don't catch teammates in teamplay
if ((teamplay == 1) && (fuel.team != self.owner.team))
{
return;
}
else if ((fuel.takedamage != DAMAGE_AIM) || (current_flames >= 30))
{
return;
}
else if ((fuel.classname == "player") && (random () > 0.75))
{
return;
}
else if (random () > 0.5)
{
return;
}
current_flames = current_flames + 1;
if (fuel.classname == "player")
{
bprint (fuel.netname);
bprint (" is on fire!!\n");
}
else if (fuel.classname == "cujo")
sprint (fuel.owner, "Your dog is aflame!!\n");
new_flame = spawn ();
// set the sucker on fire!
new_flame.enemy = fuel;
new_flame.solid = SOLID_NOT;
new_flame.angles_x = 0;
new_flame.movetype = MOVETYPE_NONE;
new_flame.effects = EF_DIMLIGHT;
new_flame.takedamage = DAMAGE_NO;
new_flame.classname = "fire";
new_flame.targetname = "";
new_flame.think = blaze_stick;
new_flame.nextthink = time;
// always points back to the player who fired the original flame
// so monsters get mad at player, not at flames!
new_flame.owner = self.owner;
setmodel (new_flame, "progs/flame2.mdl");
setsize (new_flame, '2 2 2', '2 2 2');
setorigin (new_flame, fuel.origin);
};
/*
===============
blaze_findfuel
called by blaze_stick
searches for the closest entity within a certain radius. If a qualifying entity is
found, and a random chance met, the entity is caught on fire by calling blaze_spread.
Notice there is a greater chance for players to be caught on fire, since they tend to
move around quite a bit more than monsters, and are less likely to remain near a flame
===============
*/
void (float dist) blaze_findfuel =
{
local entity head;
local entity fuel;
local float lastd;
// anything dist units away can catch flame
head = findradius (self.origin, dist);
fuel = world;
while (head)
{
if (((teamplay == 1) && (head.team != self.owner.team)) || (teamplay != 1))
{
if ((head != self.enemy) && (head.takedamage == DAMAGE_AIM))
{
// find the distance to the current entity, so we can choose the closest
// entity within the radius
lastd = vlen (self.origin - head.origin);
if (lastd < dist)
{
fuel = head;
dist = lastd;
}
}
}
head = head.chain;
}
if ((fuel != world) && (random () < 0.1))
{
blaze_spread (fuel);
}
};
/*
===============
blaze_stick
called every frame as the flame's think function. responsible for control
the flame once it has attached to an entity -- not in flight from the blaze gun!
checks for water submersion each frame
===============
*/
void () burn_entity;
void () blaze_stick =
{
local vector org;
local vector fuelsize, xv, yv, zv;
local float pc;
local float average_width;
pc = pointcontents (self.origin);
if ((pc == CONTENT_WATER) || (pc == CONTENT_SLIME))
{
// water extinguished the flame
sound (self, CHAN_WEAPON, "blaze/flhiss1.wav", 1, ATTN_NORM);
// reset inflictor so enities don't keep going for water
self.enemy.dmg_inflictor = world;
current_flames = current_flames - 1;
remove (self);
return;
}
// a dead player -- put out the flames before they respawn!
// changed to flame search in CopyBodyToQue
/*
if (self.enemy.deadflag == DEAD_RESPAWNABLE))
{
current_flames = current_flames - 1;
remove (self);
return;
}
*/
fuelsize = self.enemy.size;
// it's really the average of x_width and y_width * 2;
average_width = (fuelsize_x + fuelsize_y) * 0.5;
blaze_findfuel (average_width);
// make the flames dance, baby! dance!
if (self.enemy.classname == "monster_shambler")
pc = 0.4;
else
pc = 0.1;
fuelsize_x = fuelsize_x * pc * random ();
if (random () < 0.5)
fuelsize_x = fuelsize_x * -1;
fuelsize_y = fuelsize_y * pc * random ();
if (random () < 0.5)
fuelsize_y = fuelsize_y * -1;
fuelsize_z = fuelsize_z * pc * random ();
if ((random () < 0.5) && (self.enemy.classname != "monster_shambler"))
fuelsize_z = fuelsize_z * -1;
org = self.enemy.origin + fuelsize;
setorigin (self, org);
if (self.velocity == '0 0 0') self.avelocity = '0 0 0';
self.think = blaze_stick;
self.nextthink = time;
// targetname is used as a flag here to determine if the entity
// has already been determined to be dead and the attack_finished time
// already increased -- without the flag, the flames won't burn out
// because the attack_finished time will always be increasing
if ((self.enemy.health <= 0) && (self.targetname == "") &&
(self.enemy.classname != "monster_zombie"))
// (self.enemy.classname != "player"))
{
self.attack_finished = 7 * random () + time;
self.targetname = "already_dead";
// bprint (self.enemy.classname);
// bprint (" is dead and burning\n");
}
if (self.attack_finished <= time) burn_entity ();
};
/*
===============
burn_entity -- called by the flame
called each time attack_finished <= time, currently every second
responsible for damaging the entity the flame is attached to
zombies are a special case and recieve quite a bit more damage than
a normal monster or player so that a few flames and sometimes a single
flame, can gib them
===============
*/
void () burn_entity =
{
if ((self.enemy.health <= 0) || (self.enemy.deadflag == DEAD_RESPAWNABLE))
{
current_flames = current_flames - 1;
remove (self);
return;
}
if (self.enemy.classname != "monster_zombie")
T_Damage (self.enemy, self, self.owner, 6 * random () + 1);
else
T_Damage (self.enemy, self, self.owner, 50 * random () + 10);
if (self.enemy.classname == "player")
centerprint (self.enemy, "You're on fire!\nFind some water or armor!");
// self.think = blaze_stick;
// self.nextthink = time;
self.attack_finished = time + 1;
};
/*
===============
blaze_watercheck
called as the flame's think function from the time it is fired until it hits
and is removed or catches and entity on fire
===============
*/
void() blaze_watercheck =
{
local float pc;
pc = pointcontents (self.origin);
if ((pc == CONTENT_WATER) || (pc == CONTENT_SLIME) || (self.attack_finished <= time))
{
sound (self, CHAN_WEAPON, "blaze/flhiss1.wav", 1, ATTN_NORM);
// reset inflictor so enities don't keep going for water
remove (self);
// make the little grey particles
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_GUNSHOT);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
return;
}
self.think = blaze_watercheck;
self.nextthink = time;
};
/*
===============
blaze_touch
the touch function of an in-flight flame. responsible for setting an
entity aflame when it hits it (if the random chance is met)
===============
*/
void() blaze_touch =
{
local vector org;
local float pc;
// for debugging fire extinguishing
// other = self.owner;
pc = pointcontents (self.origin);
if (pc == CONTENT_SKY)
{
remove (self);
return;
}
else if ((pc == CONTENT_WATER) || (pc == CONTENT_SLIME))
{
remove (self);
return;
}
sound (self, CHAN_WEAPON, "blaze/flhit1.wav", 1, ATTN_NORM);
org = self.origin - 8*normalize(self.velocity);
if ((other.health) && (other.takedamage == DAMAGE_AIM))
T_Damage (other, self, self.owner, 15);
else
{
// makes a little debris appear for one frame
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_GUNSHOT);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
}
// does some radius damage, < 1/3 that of a rocket
T_RadiusDamage (self, self.owner, 35, other);
// debugging purposes
/*
bprint ("health=");
bprint (ftos (other.health));
if (other.takedamage == DAMAGE_AIM)
bprint (", DAMAGE_AIM\n");
else
bprint (", no damage\n");
*/
if (((teamplay == 1) && (other.team != self.owner.team)) || (teamplay != 1))
{
if ((other.health) && (other.takedamage == DAMAGE_AIM))
{
if ((random () < 0.6) && (current_flames < 30))
{
// set the sucker on fire!
self.enemy = other;
// used for debugging deathmatch respawns
// self.enemy = self.owner;
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NONE;
self.origin = self.enemy.origin;
self.think = blaze_stick;
self.nextthink = time;
self.attack_finished = time + 1;
self.classname = "fire";
self.targetname = "";
// point flame upright
self.angles_x = 0;
current_flames = current_flames + 1;
return;
}
}
}
BecomeExplosion ();
};
/*
===============
blaze_launch
the main firing routine, determines where the flame shoots from and where it will
go to, determines it's velocity, etc.
===============
*/
void(float ox) blaze_launch =
{
local entity old;
local vector start, finish, dir;
local float pc;
start = self.origin + '0 0 16' + v_right*ox;
makevectors (self.v_angle);
if (self.ammo_nails < 1)
{
self.weapon = W_BestWeapon ();
W_SetCurrentAmmo ();
return;
}
self.currentammo = self.ammo_nails = self.ammo_nails - 1;
makevectors (self.v_angle); // is this still used
finish = start + v_forward*600;
dir = finish - start;
// launch the flame
sound (self, CHAN_WEAPON, "blaze/flshot1.wav", 1, ATTN_NORM);
dir = normalize(dir);
newmis = spawn();
newmis.owner = self;
newmis.movetype = MOVETYPE_TOSS;
newmis.solid = SOLID_BBOX;
newmis.effects = EF_DIMLIGHT;
newmis.takedamage = DAMAGE_NO;
newmis.classname = "blaze_shot";
setmodel (newmis, "progs/flame2.mdl");
setsize (newmis, '2 2 2', '2 2 2');
setorigin (newmis, start);
// add player's velocity to the flames velocity for maximum effect
newmis.velocity = (self.velocity * 0.5) + (dir * 1000);
newmis.angles = vectoangles(newmis.velocity);
// turn the flame on it's side, widest end away from player
newmis.angles_x = newmis.angles_x + 90;
// give the player a little kickback
self.velocity = self.velocity - (dir * 125);
// will burn for 8 seconds
newmis.attack_finished = time + 8;
// continously check for water
newmis.nextthink = time + 0.1;
newmis.think = blaze_watercheck;
newmis.touch = blaze_touch;
// launch_flame (start, dir);
self.punchangle_x = -2;
};
void () blaze_attack1 = [$nailatt1, blaze_attack2]
{
self.effects = self.effects | EF_MUZZLEFLASH;
// if (!self.button0)
// {
// player_run ();
// return;
// }
self.weaponframe = self.weaponframe + 1;
if (self.weaponframe == 9) self.weaponframe = 1;
SuperDamageSound();
blaze_launch (4);
self.attack_finished = time + 0.2;
};
//============================================================================
void () blaze_attack2 = [$nailatt1, blaze_attack3]
{
if (!self.button0)
{
player_run ();
return;
}
self.weaponframe = self.weaponframe + 1;
if (self.weaponframe == 9) self.weaponframe = 1;
self.attack_finished = time + 0.2;
};
//============================================================================
void () blaze_attack3 = [$nailatt2, blaze_attack4]
{
self.effects = self.effects | EF_MUZZLEFLASH;
if (!self.button0)
{
player_run ();
return;
}
self.weaponframe = self.weaponframe + 1;
if (self.weaponframe == 9) self.weaponframe = 1;
SuperDamageSound();
blaze_launch (-4);
self.attack_finished = time + 0.2;
};
//============================================================================
void () blaze_attack4 = [$nailatt2, blaze_attack1]
{
if (!self.button0)
{
player_run ();
return;
}
self.weaponframe = self.weaponframe + 1;
if (self.weaponframe == 9) self.weaponframe = 1;
self.attack_finished = time + 0.2;
};